"""
Word文档生成模块
基于模板样式生成接口文档
"""

import json
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.shared import OxmlElement, qn
from typing import Dict, List, Any, Optional


class DocGenerator:
    """Word文档生成器"""
    
    def __init__(self, template_path: Optional[str] = None):
        """
        初始化文档生成器
        
        Args:
            template_path: 模板文档路径，如果为None则创建空文档
        """
        if template_path:
            self.doc = Document(template_path)
        else:
            self.doc = Document()
        
        # 设置默认样式
        self._setup_styles()
    
    def _setup_styles(self):
        """设置文档样式"""
        # 设置正文字体
        style = self.doc.styles['Normal']
        font = style.font
        font.name = '宋体'
        font.size = Pt(12)
        
        # 设置段落间距
        paragraph_format = style.paragraph_format
        paragraph_format.space_after = Pt(6)
    
    def add_title(self, title: str, level: int = 1):
        """
        添加标题
        
        Args:
            title: 标题文本
            level: 标题级别 (1-4)
        """
        heading_style = f'Heading {level}'
        heading = self.doc.add_heading(title, level=level)
        
        # 设置标题样式
        if level == 1:
            heading.style.font.size = Pt(16)
            heading.style.font.bold = True
        elif level == 2:
            heading.style.font.size = Pt(14)
            heading.style.font.bold = True
        elif level == 3:
            heading.style.font.size = Pt(13)
            heading.style.font.bold = True
        else:
            heading.style.font.size = Pt(12)
            heading.style.font.bold = True
    
    def add_api_section(self, api_data: Dict[str, Any], section_number: str, config=None):
        """
        添加单个API接口章节
        
        Args:
            api_data: 解析后的API数据
            section_number: 章节编号，如 "2.1.1.1"
            config: 配置对象
        """
        basic_info = api_data['basic_info']
        request_info = api_data['request_info']
        response_info = api_data['response_info']
        
        # 添加接口标题
        api_title = f"{section_number} {basic_info['name']}"
        self.add_title(api_title, level=4)
        
        # 1. 接口信息
        self._add_api_basic_info(basic_info)
        
        # 2. 请求参数说明
        self._add_request_parameters(request_info, config)
        
        # 3. 响应参数说明
        self._add_response_parameters(response_info, config)
        
        # 添加分页符（可选）
        if config and config.add_page_break:
            self.doc.add_page_break()
    
    def _add_api_basic_info(self, basic_info: Dict[str, Any]):
        """添加接口基本信息"""
        # 接口信息表格
        table = self.doc.add_table(rows=4, cols=2)
        table.style = 'Table Grid'
        table.alignment = WD_TABLE_ALIGNMENT.LEFT
        
        # 设置表格列宽
        for cell in table.columns[0].cells:
            cell.width = Inches(1.5)
        for cell in table.columns[1].cells:
            cell.width = Inches(4)
        
        # 填充接口信息
        info_items = [
            ('接口名称', basic_info['name']),
            ('请求方法', basic_info['method']),
            ('请求URL', basic_info['url']),
            ('接口描述', basic_info['description'] or '暂无描述')
        ]
        
        for i, (label, value) in enumerate(info_items):
            row = table.rows[i]
            # 设置标签列
            label_cell = row.cells[0]
            label_cell.text = label
            label_cell.paragraphs[0].runs[0].font.bold = True
            
            # 设置值列
            value_cell = row.cells[1]
            value_cell.text = value
            
            # 设置字体
            for cell in [label_cell, value_cell]:
                for paragraph in cell.paragraphs:
                    for run in paragraph.runs:
                        run.font.name = '宋体'
                        run.font.size = Pt(11)
        
        self.doc.add_paragraph()  # 添加空行
    
    def _add_request_parameters(self, request_info: Dict[str, Any], config=None):
        """添加请求参数说明"""
        self.doc.add_heading('请求参数说明', level=5)
        
        # Header参数
        if request_info['headers']:
            self.doc.add_paragraph('Header参数：', style='Heading 6')
            self._add_parameter_table(request_info['headers'], config)
        
        # Query参数
        if request_info['query_params']:
            self.doc.add_paragraph('Query参数：', style='Heading 6')
            self._add_parameter_table(request_info['query_params'], config)
        
        # Body参数
        if request_info['body']['raw'] or request_info['body']['parameters']:
            self.doc.add_paragraph('Body参数：', style='Heading 6')
            
            # 如果有raw数据，显示JSON示例
            if request_info['body']['raw'] and config and config.include_request_body_example:
                self.doc.add_paragraph('请求体示例：')
                self._add_json_code_block(request_info['body']['raw'], config)
            
            # 如果有参数表，显示参数说明
            if request_info['body']['parameters']:
                self.doc.add_paragraph('参数说明：')
                self._add_parameter_table(request_info['body']['parameters'], config)
        
        self.doc.add_paragraph()  # 添加空行
    
    def _add_response_parameters(self, response_info: Dict[str, Any], config=None):
        """添加响应参数说明"""
        self.doc.add_heading('响应参数说明', level=5)
        
        examples = response_info['examples']
        if not examples:
            self.doc.add_paragraph('暂无响应示例')
            return
        
        # 找到默认的成功响应示例
        default_example = None
        for example in examples:
            if example['is_default'] and example['code'] == '200':
                default_example = example
                break
        
        if not default_example and examples:
            default_example = examples[0]
        
        if default_example:
            # 响应示例
            if config and config.include_response_example:
                self.doc.add_paragraph('响应示例：')
                if default_example['raw_response']:
                    self._add_json_code_block(default_example['raw_response'], config)
            
            # 响应参数说明
            if default_example['schema']:
                self.doc.add_paragraph('响应参数说明：')
                self._add_schema_table(default_example['schema'], '', config)
        
        self.doc.add_paragraph()  # 添加空行
    
    def _add_parameter_table(self, parameters: List[Dict[str, Any]], config=None):
        """添加参数表格"""
        if not parameters:
            self.doc.add_paragraph('无参数')
            return
        
        # 根据配置决定是否显示示例列
        show_example = config and config.show_example_column
        
        # 创建参数表格 - 根据配置决定列数
        if show_example:
            # 5列：参数名、参数类型、是否必填、示例、描述
            table = self.doc.add_table(rows=len(parameters) + 1, cols=5)
            headers = ['参数名', '参数类型', '是否必填', '示例', '描述']
        else:
            # 4列：参数名、参数类型、是否必填、描述
            table = self.doc.add_table(rows=len(parameters) + 1, cols=4)
            headers = ['参数名', '参数类型', '是否必填', '描述']
        
        table.style = 'Table Grid'
        table.alignment = WD_TABLE_ALIGNMENT.LEFT
        
        # 设置表头
        header_row = table.rows[0]
        for i, header in enumerate(headers):
            cell = header_row.cells[i]
            cell.text = header
            # 设置表头样式
            for paragraph in cell.paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                for run in paragraph.runs:
                    run.font.bold = True
                    run.font.name = '宋体'
                    run.font.size = Pt(11)
        
        # 填充参数数据
        for i, param in enumerate(parameters):
            row = table.rows[i + 1]
            
            row.cells[0].text = param['key']
            row.cells[1].text = param['type'].capitalize()  # 首字母大写
            row.cells[2].text = '是' if param['required'] else '否'
            
            if show_example:
                # 有示例列的情况
                row.cells[3].text = param['value'] or ''
                row.cells[4].text = param['description']
            else:
                # 无示例列的情况，将示例值合并到描述中
                description = param['description']
                if param['value']:
                    description = f"{description}\n示例：{param['value']}" if description else f"示例：{param['value']}"
                row.cells[3].text = description
            
            # 设置单元格样式
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    for run in paragraph.runs:
                        run.font.name = '宋体'
                        run.font.size = Pt(10)
        
        self.doc.add_paragraph()  # 添加空行
    
    def _add_schema_table(self, schema: Dict[str, Any], prefix: str = '', config=None):
        """添加响应结构表格"""
        if not schema or schema.get('type') != 'object':
            return
        
        properties = schema.get('properties', {})
        if not properties:
            return
        
        # 收集所有参数（包括嵌套的）
        all_params = []
        required_fields = schema.get('required', [])
        self._collect_schema_params(properties, all_params, '', required_fields)
        
        if not all_params:
            return
        
        # 根据配置决定是否显示示例列
        show_example = config and config.show_example_column
        
        # 创建参数表格 - 根据配置决定列数
        if show_example:
            # 6列：参数名、参数类型、是否必填、父节点、示例、描述
            table = self.doc.add_table(rows=len(all_params) + 1, cols=6)
            headers = ['参数名', '参数类型', '是否必填', '父节点', '示例', '描述']
        else:
            # 5列：参数名、参数类型、是否必填、父节点、描述
            table = self.doc.add_table(rows=len(all_params) + 1, cols=5)
            headers = ['参数名', '参数类型', '是否必填', '父节点', '描述']
        
        table.style = 'Table Grid'
        table.alignment = WD_TABLE_ALIGNMENT.LEFT
        
        # 设置表头
        header_row = table.rows[0]
        for i, header in enumerate(headers):
            cell = header_row.cells[i]
            cell.text = header
            # 设置表头样式
            for paragraph in cell.paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                for run in paragraph.runs:
                    run.font.bold = True
                    run.font.name = '宋体'
                    run.font.size = Pt(11)
        
        # 填充参数数据
        for i, param in enumerate(all_params):
            if i + 1 >= len(table.rows):
                break
                
            row = table.rows[i + 1]
            
            row.cells[0].text = param['name']
            row.cells[1].text = param['type']
            row.cells[2].text = param['required']
            row.cells[3].text = param['parent']
            
            if show_example:
                # 有示例列的情况
                row.cells[4].text = param.get('example', '')
                row.cells[5].text = param['description']
            else:
                # 无示例列的情况
                row.cells[4].text = param['description']
            
            # 设置单元格样式
            for cell in row.cells:
                for paragraph in cell.paragraphs:
                    for run in paragraph.runs:
                        run.font.name = '宋体'
                        run.font.size = Pt(10)
        
        self.doc.add_paragraph()  # 添加空行
    
    def _collect_schema_params(self, properties: Dict[str, Any], params_list: List[Dict], parent_path: str = '', required_fields: List[str] = None):
        """递归收集schema参数，包括嵌套对象"""
        if required_fields is None:
            required_fields = []
            
        for prop_name, prop_schema in properties.items():
            param_type = prop_schema.get('type', 'unknown')
            
            # 确定父节点
            if parent_path:
                parent = parent_path
                full_name = prop_name  # 在表格中只显示当前字段名
            else:
                parent = '-'
                full_name = prop_name
            
            # 检查是否必填
            is_required = prop_name in required_fields
            
            # 基本参数信息
            param_info = {
                'name': full_name,
                'type': param_type.capitalize(),
                'required': '是' if is_required else '否',
                'parent': parent,
                'example': str(prop_schema.get('example', '')),
                'description': self._get_param_description(prop_schema, prop_name)
            }
            
            params_list.append(param_info)
            
            # 如果是对象类型，递归处理其属性
            if param_type == 'object' and 'properties' in prop_schema:
                nested_properties = prop_schema.get('properties', {})
                nested_required = prop_schema.get('required', [])
                if nested_properties:
                    # 为嵌套对象设置父节点路径
                    new_parent = prop_name if not parent_path else f"{parent_path}.{prop_name}"
                    self._collect_schema_params(nested_properties, params_list, new_parent, nested_required)
            
            # 如果是数组类型，检查数组项的类型
            elif param_type == 'array' and 'items' in prop_schema:
                items_schema = prop_schema.get('items', {})
                if items_schema.get('type') == 'object' and 'properties' in items_schema:
                    # 数组中的对象
                    nested_properties = items_schema.get('properties', {})
                    nested_required = items_schema.get('required', [])
                    if nested_properties:
                        new_parent = f"{prop_name}[]" if not parent_path else f"{parent_path}.{prop_name}[]"
                        self._collect_schema_params(nested_properties, params_list, new_parent, nested_required)
    
    def _get_param_description(self, prop_schema: Dict[str, Any], prop_name: str) -> str:
        """获取参数描述，包括示例值"""
        description = prop_schema.get('description', '')
        example = prop_schema.get('example', '')
        
        # 根据模板的格式，某些特殊字段有特定描述
        type_name = prop_schema.get('type', '')
        
        if not description:
            # 根据字段名和类型生成默认描述
            if 'id' in prop_name.lower():
                description = f"{prop_name}标识"
            elif type_name == 'boolean':
                description = "布尔值"
            elif type_name == 'array':
                description = f"示例{prop_name}"
            elif type_name == 'object':
                description = f"{prop_name}信息(预留)"
            else:
                description = f"{prop_name}"
        
        # 如果有示例值，添加到描述中
        if example and str(example).strip():
            if description:
                description = f"{description}"
            else:
                description = f"示例值：{example}"
                
        return description
    
    def _add_json_code_block(self, json_text: str, config=None):
        """添加JSON代码块"""
        try:
            # 尝试格式化JSON
            parsed_json = json.loads(json_text)
            indent = config.json_indent if config and config.format_json else 2
            if config and config.format_json:
                formatted_json = json.dumps(parsed_json, ensure_ascii=False, indent=indent)
            else:
                formatted_json = json_text
        except:
            formatted_json = json_text
        
        # 添加代码段落
        code_paragraph = self.doc.add_paragraph()
        code_run = code_paragraph.add_run(formatted_json)
        
        # 设置代码样式
        code_run.font.name = 'Consolas'
        code_run.font.size = Pt(10)
        
        # 设置段落样式
        code_paragraph.paragraph_format.left_indent = Inches(0.5)
        code_paragraph.paragraph_format.space_before = Pt(6)
        code_paragraph.paragraph_format.space_after = Pt(6)
        
        self.doc.add_paragraph()  # 添加空行
    
    def save(self, output_path: str):
        """
        保存文档
        
        Args:
            output_path: 输出文件路径
        """
        self.doc.save(output_path)
        print(f"文档已保存到: {output_path}")


if __name__ == "__main__":
    # 测试代码
    doc_gen = DocGenerator()
    
    # 测试数据
    test_api = {
        'basic_info': {
            'name': '测试接口',
            'method': 'POST',
            'url': 'http://example.com/api/test',
            'description': '这是一个测试接口'
        },
        'request_info': {
            'headers': [
                {'key': 'Content-Type', 'type': 'string', 'required': True, 'value': 'application/json', 'description': '内容类型'}
            ],
            'query_params': [],
            'body': {
                'raw': '{"name": "test", "value": 123}',
                'parameters': []
            }
        },
        'response_info': {
            'examples': [
                {
                    'is_default': True,
                    'code': '200',
                    'raw_response': '{"success": true, "data": {"id": 1}}',
                    'schema': {
                        'type': 'object',
                        'properties': {
                            'success': {'type': 'boolean', 'example': True},
                            'data': {'type': 'object', 'properties': {'id': {'type': 'integer', 'example': 1}}}
                        }
                    }
                }
            ]
        }
    }
    
    doc_gen.add_api_section(test_api, "2.1.1.1")
    doc_gen.save("../output/test_output.docx")
